<template>
  <div class="inline-edit" @click.stop="handleClick" ref="wrapper">
    <input
      v-model="innerValue"
      v-if="isEditing"
      placeholder="文本不能为空"
      ref="inputRef"
      :class="{ 'input-error': !validateCheck}"
      class="ant-input"
    />
    <slot v-else :text="innerValue"><span>{{innerValue}}</span></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, watch, computed, nextTick } from 'vue'
import useKeyPress from '../hooks/useKeyPress'
import useClickOutside from '../hooks/useClickOutside'
export default defineComponent({
  name: 'inline-edit',
  props: {
    value: {
      type: String,
      required: true
    }
  },
  emits: ['change'],
  setup (props, context) {
    const innerValue = ref(props.value)
    watch(() => props.value, (newValue) => {
      innerValue.value = newValue
    })
    const wrapper = ref<null | HTMLElement>(null)
    const inputRef = ref<null | HTMLInputElement>(null)
    const isOutside = useClickOutside(wrapper)
    let cachedOldValue = ''
    const isEditing = ref(false)
    const handleClick = () => {
      isEditing.value = true
    }
    const validateCheck = computed(() => innerValue.value.trim() !== '')
    watch(isEditing, async (isEditing) => {
      if (isEditing) {
        cachedOldValue = innerValue.value
        await nextTick()
        if (inputRef.value) {
          inputRef.value.focus()
        }
      }
    })
    watch(isOutside, (newValue) => {
      if (!validateCheck.value) {
        return
      }
      if (newValue && isEditing.value) {
        isEditing.value = false
        context.emit('change', innerValue.value)        
      }
      isOutside.value = false
    })
    useKeyPress('Enter', () => {
      if (!validateCheck.value) {
        return
      }
      if (isEditing.value) {
        isEditing.value = false
        context.emit('change', innerValue.value)
      }
    })
    useKeyPress('Escape', () => {
      if (isEditing.value) {
        isEditing.value = false
        innerValue.value = cachedOldValue
      }
    })
    return {
      handleClick,
      innerValue,
      isEditing,
      wrapper,
      inputRef,
      validateCheck
    }
  }
})
</script>

<style>
.inline-edit {
  cursor: pointer;
}
.ant-input.input-error {
  border: 1px solid #f5222d;
}
.ant-input.input-error:focus {
  border-color:  #f5222d;
}
.ant-input.input-error::placeholder {
  color: #f5222d;
}
</style>
